//////////////////////////////////////////////////////////////////////
// HemiOctmapSampler.h
//
// SHEN Fangyang
// me@shenfy.com
//
// Copyright (C) SHEN Fangyang, 2011, All rights reserved.
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//  Brief Description
//
//	Hemi-Octahedron map sampler, as in
//	[Engelhardt08] Octahedron Environment Maps, VMV08
//
//////////////////////////////////////////////////////////////////////
#pragma once

#include <IImgSampler.h>
#include <Logger.h>
#include <cmath>

#pragma comment (lib, W32LIB_BIN_FILE)

namespace grflib
{
	namespace image
	{
		//Class declaration

		//////////////////////////////////////
		//Hemi-octahedral map Sampler 
		//////////////////////////////////////
		template<typename T>
		class CHemiOctmapSampler :
			public IImgSampler<T>
		{
		public:
			CHemiOctmapSampler(void);
			virtual ~CHemiOctmapSampler(void);

			//texture access
			T texHemiOct(const float &x, const float &y, const float &z, const UINT &c);

			//conversion between 3D direction vector and 2D (u,v) coordinates
			static void Tex3DTo2D(const float &x, const float &y, const float &z, /*input*/
								  float &u, float &v /*output*/);
			static void Tex2DTo3D(const float &u, const float &v, /*input*/
								  float &x, float &y, float &z /*output*/);

		protected:

		};

		//Class definition
		template<typename T>
		CHemiOctmapSampler<T>::CHemiOctmapSampler()
		{
		}

		template<typename T>
		CHemiOctmapSampler<T>::~CHemiOctmapSampler()
		{
		}

		template<typename T>
		void CHemiOctmapSampler<T>::Tex3DTo2D(const float &x, const float &y, const float &z, /*input*/
											  float &u, float &v /*output*/)
		{
			float sum;
			float px, py, pz;

			sum = abs(x) + abs(y) + abs(z);
			px = x / sum;
			py = y / sum;
			pz = z / sum;

			_ASSERT(py >= 0.0f); //upper hemisphere only!

			u = px - pz;
			v = px + pz;

			//map to [0,1]
			u = (u + 1.0f) / 2.0f;
			v = 1.0f - ((v + 1.0f) / 2.0f);
		}

		template<typename T>
		void CHemiOctmapSampler<T>::Tex2DTo3D(const float &u, const float &v, /*input*/
											  float &x, float &y, float &z /*output*/)
		{
			float un, vn;

			//map to [-1,1]
			un = u * 2.0f - 1.0f;
			vn = (1.0f - v) * 2.0f - 1.0f;

			x = (un + vn) / 2.0f;
			z = (vn - un) / 2.0f;
			y = 1.0f - abs(x) - abs(z);

			math::Normalize3D(x, y, z);
		}

		template<typename T>
		T CHemiOctmapSampler<T>::texHemiOct(const float &x, const float &y, const float &z, const UINT &c)
		{
			float u = 0.0f, v = 0.0f;

			//convert 3D direction vector to 2D (u,v)
			Tex3DTo2D(x, y, z, u, v);

			//bilinear sampling
			T result = tex2D(u, v, c);
			return result;
		}
	} //namespace namespace image
} //namespace namespace grflib